import re
import tkinter
from enum import Enum
from pprint import pprint
import os.path

from . import BaseView
from tkinter import Frame, Text, Scrollbar
from tkinter.font import Font

from PIL import Image, ImageTk
from tabulate import tabulate


class MarkdownView(Frame, BaseView):
    def __init__(self, parent, delegetor):
        super().__init__(parent)
        BaseView.__init__(self, delegetor)
        self.font = ('宋体', 14)
        self.text_plate = Text(self, font=self.font, undo=True, state='disabled')
        self.scrollbal = Scrollbar(self, orient='vertical')

        self.scrollbal.pack(side='right', fill='y')
        self.text_plate.pack(side='right', fill='both')
        self.scrollbal['command'] = self.text_plate.yview
        self.text_plate['yscrollcommand'] = self.scrollbal.set

        self.text_plate.pack(fill='both', expand=True)

        self.path = None
        self.photos = list()

        self.text_plate.bind('<Double-Button-3>', self.open_by_others)
        self.text_plate.bind("<KeyPress>", lambda e: "break")

    def open(self, path):
        self.open_raw(path)
        # self.open_render(path)

    def open_render(self, path, verbose=True):
        print("rendering...")
        self.path = path
        self.text_plate['state'] = 'normal'
        self.text_plate.delete("1.0", "end")

        font_name, font_size = self.text_plate['font'].split(" ")
        font_size = int(font_size)

        self.text_plate.tag_config("heading_1", font=(font_name, font_size + 3, "bold"))
        self.text_plate.tag_config("heading_2", font=(font_name, font_size + 2, "bold"))
        self.text_plate.tag_config("heading_3", font=(font_name, font_size + 1, "bold"))
        self.text_plate.tag_config("heading_4", font=(font_name, font_size, "bold"))
        self.text_plate.tag_config("heading_5", font=(font_name, font_size - 1, "bold"))
        self.text_plate.tag_config("code", background="#F8F8F8", selectbackground="#000000")

        with open(path, 'r', encoding="utf-8") as f:
            text = f.read()
            ast = md_parse(text, verbose=verbose)
            print("\n\n\n")
        stack = list()
        for state, element, val, comment in ast:
            if element == ELEMENT.HEAD:
                self.text_plate.insert("end", val + "\n", "heading_%d" % comment)
            elif element == ELEMENT.PASSAGE:
                self.text_plate.insert("end", val + "\n")
            elif element == ELEMENT.IMAGE:
                # locate the image in the center at init, but when resize the windows, it will fail.
                # Using method of padding whitespace before the image.
                unit = Font(self.text_plate, self.font).measure(" ")
                self.text_plate.update()  # when use the info,must update before using.
                tw = self.text_plate.winfo_width()
                img_path = os.path.join(os.path.dirname(path), val)
                if os.path.isfile(img_path):
                    photo = ImageTk.PhotoImage(Image.open(img_path))
                else:
                    self.pprint("无法打开文件", img_path)
                    continue
                pw = photo.width()
                num = int((tw - pw) / 2 / unit)
                self.text_plate.insert("end", " " * num)
                self.photos.append(photo)
                self.text_plate.image_create("end", image=photo, align=tkinter.CENTER)
                self.text_plate.insert("end",  "\n")
            elif element == ELEMENT.CODE_START:
                pass
            elif element == ELEMENT.CODE_BODY:
                self.text_plate.insert("end", val + "\n", "code")
            elif element == ELEMENT.CODE_END:
                pass
            elif element == ELEMENT.TABLE_HEADER:
                stack.append(val)  # `header` push.
            elif element == ELEMENT.TABLE_BODY:
                stack.append(val)
            elif element == ELEMENT.TABLE_END:
                table = tabulate(stack[1:], headers=stack[0], tablefmt="grid")
                stack.clear()
                self.text_plate.insert("end", table + "\n")
            elif element == ELEMENT.SEPARATOR:
                unit = Font(self.text_plate, self.font).measure("-")
                self.text_plate.update()  # when use the info,must update before using.
                tw = self.text_plate.winfo_width()
                num = int(tw / unit)
                self.text_plate.insert("end", "-" * num + "\n")
            elif element == ELEMENT.NULL:
                pass
            else:
                if verbose:
                    print(state, element, val, comment, sep='\t')


    def open_raw(self, path):
        super().open(path)
        self.path = path
        self.text_plate['state'] = 'normal'
        self.text_plate.delete("1.0", "end")
        with open(path, 'r', encoding="utf-8") as f:
            text = f.read()
        self.text_plate.insert("1.0", text)
        self.text_plate['state'] = 'disabled'

    def close(self):
        self.photos.clear()
        return super().close()

    def file_extension(self):
        return ".md"


class ELEMENT(Enum):
    HEAD = 1
    IMAGE = 2
    PASSAGE = 3
    CODE_START = 4
    CODE_BODY = 5
    CODE_END = 6
    TABLE_HEADER = 7
    TABLE_BODY = 8
    TABLE_END = 9
    SEPARATOR = 10
    NULL = 11


class State(Enum):
    NULL = 1
    CODE = 2
    TABLE = 3


def md_parse(text: str, verbose=False):
    """
    解析markdown文件。返回三元组(类型, 值, 备注)
    :param text:
    :return:
    """
    state = State.NULL
    res = list()
    lines = text.split('\n')
    p_line = 0
    len_line = len(lines)
    while p_line < len_line:
        line = lines[p_line]
        p_line += 1
        element, val, comment = None, None, None
        if len(line) == 0:
            continue
        if state == State.NULL:
            if line[0] == '#':  # 标题
                element = ELEMENT.HEAD
                val = line[line.find(" "):]
                comment = len(line) - len(val)
                if verbose:
                    print(state, line, element, val, comment, sep='\t')
            elif line[0] == '!':  # 图片
                element = ELEMENT.IMAGE
                val = re.search(r"\(.*\)", line)[0][1:-1]
                comment = None
                if verbose:
                    print(state, line, element, val, comment, sep='\t')
            elif line[0] == '`' and len(line) >= 3 and line[:3] == '```':  # 代码
                if verbose:
                    print("[%s -> %s]" % (state, State.CODE), line, sep='\t')
                state = State.CODE
                element = ELEMENT.CODE_START
                val = line[3:]
                comment = None
            elif line[0] == "|" and line.count("|") >= 2:  # 表
                if verbose:
                    print("[%s -> %s]" % (state, State.TABLE), element, val, comment, sep='\t')
                state = State.TABLE
                element = ELEMENT.TABLE_HEADER
                val = line[1:-1].split("|")
                comment = None
            elif len(line) >= 3 and line[:3] == "---":  # 分隔符
                element = ELEMENT.SEPARATOR
                val = None
                comment = None
                if verbose:
                    print(state, line, element, val, comment, sep='\t')
            else:  # 段落
                element = ELEMENT.PASSAGE
                val = line
                comment = None
                if verbose:
                    print(state, line, element, val, comment, sep='\t')
        elif state == State.CODE:
            if line[0] == '`' and len(line) >= 3 and line[:3] == '```':  # 代码结束
                if verbose:
                    print("\n[%s -> %s]" % (state, State.NULL), line)
                state = State.NULL
                element = ELEMENT.CODE_END
                val = line
                comment = None
            else:
                state = State.CODE
                element = ELEMENT.CODE_BODY
                val = line
                comment = None
                if verbose:
                    print(".", end="")
        elif state == State.TABLE:
            if line[0] == '|':
                element = ELEMENT.TABLE_BODY
                val = line[1:-1].split("|")
                if len(set(val)) == 1:  # the collar
                    element = ELEMENT.NULL
                comment = None
                if verbose:
                    print(state, line, element, val, comment, sep='\t')
            else:
                # table has ended, return to the last line.
                p_line -= 1
                element = ELEMENT.TABLE_END
                val = None
                comment = None
                if verbose:
                    print(state, line, element, val, comment, sep='\t')
                    print("\n[%s -> %s]" % (state, State.NULL), line)
                state = State.NULL
                # continue
        assert element is not None
        res.append((state, element, val, comment))
    return res


if __name__ == '__main__':
    with open(r"C:\Users\xzh\Desktop\test.md", 'r', encoding="utf-8") as f:
        text = f.read()
        pprint(md_parse(text, verbose=True))
    # root = Tk()
    # txt = MarkdownView(root)
    # txt.pack()
    # txt.open(r"C:\Users\xzh\Desktop\test.md")
    # root.mainloop()